#include "rs485.h"
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>

#include <sys/types.h>
#include <unistd.h>
#include "wontec_wt184.h"
#include "wontec_wtais42.h"
#include "wontec_485.h"
#include "string.h"

#include "procedure.h"


CRs485::CRs485()
{
    m_idQueueMsg = 0;
    m_fd = -1;
    m_rts_pin = 0;
    for(int i=0;i<WONTEC_MAX_DEVID;i++)
    {
        m_completeCbFunc[i] = NULL;
        m_completeCbData[i] = NULL;
    }

    pthread_mutex_init(&m_mutexCheckRecv,NULL);
    
}
CRs485::~CRs485()
{
    if(m_ExitThreadFlag==0)
    {
        m_ExitThreadFlag = 1;
        usleep(200);
    }

    for(int i=0;i<WONTEC_MAX_DEVID;i++)
    {
        m_completeCbFunc[i] = NULL;

        /*if(m_completeCbData[i])
        {
            delete m_completeCbData[i];
        }*/
        m_completeCbData[i] = NULL;
    }
    pthread_mutex_destroy(&m_mutexCheckRecv);
}

int CRs485::openPort(int portNum, unsigned int pinRTS,serialConfig * ptrSerialConfig)
{
    printf("portnum:%d,pinValue:%d\n",portNum,pinRTS);
    m_gpioHandle = CGpio::getInstance();
    m_rts_pin = pinRTS;
    m_gpioHandle->GPIO_OutEnable(m_rts_pin);

    m_gpioHandle->GPIO_OutClear(m_rts_pin);

    printf("%c,%c,%c\n",ptrSerialConfig->databits,ptrSerialConfig->stopbits,ptrSerialConfig->parity);
    int ret = OpenPort( portNum, 115200, '8', '1', 'N');
    //int ret = CSerial::OpenPort(6,115200,ptrSerialConfig->databits,
    //ptrSerialConfig->stopbits,ptrSerialConfig->parity);

    int res = pthread_create( &m_msg_thread_handle, NULL, ReceiveMsgFunc, (void*)this );
    if(res!=0)
    {
        printf("create ReceiveMsg thread failed\n");
    }

    
    return ret;

}

int CRs485::send(unsigned char * buff, int len)
{
    int ret = 0;
    m_gpioHandle = CGpio::getInstance();
    
    m_gpioHandle->GPIO_OutEnable(m_rts_pin);

    m_gpioHandle->GPIO_OutSet(m_rts_pin);
    ret = CSerial::WritePort((char*)buff,len);
    //usleep(1000);
    m_gpioHandle->GPIO_OutClear(m_rts_pin);

    return ret;
}

void CRs485::closePort(void)
{
    m_gpioHandle->GPIO_OutDisable(m_rts_pin);
    CSerial::ClosePort();
    msgctl(m_idQueueMsg,IPC_RMID,NULL);
} 

void CRs485::setQueueMsgId(int keyIn)
{
    m_idQueueMsg = keyIn;
}

int CRs485::getQueueMsgId(void)
{
    return m_idQueueMsg;
}

// int CRs485::PackagePro( char* Buf, int len )
// {
//     int lenTmp = (len>10)?10:len;
//     printf("rs485 recv data len:%d\n",len);
//     if(lenTmp)
//     {
//         for(int i=0;i<lenTmp;i++)
//         {
//             printf("%02x,",Buf[i]);
//         }
//         printf("\n");
//     }
//     //this->send((unsigned char *)Buf,len);
// }

void* ReceiveMsgFunc(void* lparam)
{
	CRs485 *pSer = (CRs485*)lparam;
    int flagPrint = 0;
	//������¼�����
    printf("enter in rs485 cmd queue msg recv thread\n");
	while( 1 )
	{
        //�յ��˳��¼��������߳�
		if( pSer->m_ExitThreadFlag )
		{
			printf("break111\n");
			break;
		}

        wontec_queue_msg ctlMsg;
        
        //stMsgFrame.type = 1;
        int lenRecv = msgrcv(pSer->getQueueMsgId(), &ctlMsg, sizeof(wontec_msg_def), QUEUE_MSG_TYPE_RS485, IPC_NOWAIT);
        if(lenRecv>0)
        {
            printf("recv queue message\n");


            //pCan->WriteCanPort(&stMsgFrame.frame);
            //printf("opcode[%d],ele_num[%d]\n",ctlMsg.ctlFrame.opcode,ctlMsg.ctlFrame.ele_index);
            pSer->cmdAct(&(ctlMsg.wontecMsg));
        }
        if((lenRecv<0)&&(flagPrint == 0))
        {
            flagPrint = 1;
            perror("msgrcv in ReceiveMsgFunc");
            printf("queueId:%d,sizeof(wontec_msg_def):%d\n",pSer->getQueueMsgId(),sizeof(wontec_msg_def));
        }
        usleep(100);
	}

	printf( "ReceiveMsgFunc finished\n");
	pthread_detach(pthread_self());
	pthread_exit( NULL );
	return 0;
}

void CRs485::cmdAct(void * dataIn)
{
    wontec_msg_def * ptrMsgRecv = (wontec_msg_def *)dataIn;

    if(ptrMsgRecv->tarDev == WONTEC_WT184_AIR_PUMP)
    {
        wontec_cmd stWtCmd;
        unsigned char lenData = 0;
        unsigned char buff[MAX_WT_BUFF_LEN];

        //unsigned char resetCmd[10] = {0x3E,0x30,0x31,0x47,0x36,0x31,0x35,0x38,0x0d,0x0a};
        
        memset(&stWtCmd,0,sizeof(wontec_cmd));
        stWtCmd.func_code = ptrMsgRecv->funcCode;
        stWtCmd.datalen = (ptrMsgRecv->paramLen > MAX_WT_BUFF_LEN)?MAX_WT_BUFF_LEN:ptrMsgRecv->paramLen;
        memcpy(stWtCmd.data,ptrMsgRecv->paramData,stWtCmd.datalen);
        set_wt184_data(&stWtCmd,buff, &lenData);
        //lenData = 10;
        //memcpy(buff,resetCmd,10);

        //printf("send to rs485,len:%d\n",lenData);
        this->send(buff,lenData);
    }
    else if(ptrMsgRecv->tarDev >= WONTEC_WTAIS42_AIR_PUMP_Z 
         && ptrMsgRecv->tarDev <= WONTEC_WTAIS42_X)
    {
        wontec_cmd stWtCmd;
        unsigned char lenData = 0;
        unsigned char buff[MAX_WT_BUFF_LEN];

        //unsigned char resetCmd[10] = {0x3E,0x30,0x31,0x47,0x36,0x31,0x35,0x38,0x0d,0x0a};
        
        memset(&stWtCmd,0,sizeof(wontec_cmd));
        stWtCmd.func_code = ptrMsgRecv->funcCode;
        stWtCmd.datalen = (ptrMsgRecv->paramLen > MAX_WT_BUFF_LEN)?MAX_WT_BUFF_LEN:ptrMsgRecv->paramLen;
        memcpy(stWtCmd.data,ptrMsgRecv->paramData,stWtCmd.datalen);

        set_wtais_data(dp1_ele_addr_arr[ptrMsgRecv->tarDev-1],&stWtCmd,buff,&lenData);
        //set_wt184_data(&stWtCmd,buff, &lenData);
        //lenData = 10;
        //memcpy(buff,resetCmd,10);

        //printf("send to rs485,len:%d\n",lenData);
        this->send(buff,lenData);
        /* code */
    }
    else if(WONTEC_WTAIS42_JAW == ptrMsgRecv->tarDev )
    {
        wontec_cmd stWtCmd;
        unsigned char lenData = 0;
        unsigned char buff[MAX_WT_BUFF_LEN];

        //unsigned char resetCmd[10] = {0x3E,0x30,0x31,0x47,0x36,0x31,0x35,0x38,0x0d,0x0a};
        
        memset(&stWtCmd,0,sizeof(wontec_cmd));
        stWtCmd.func_code = ptrMsgRecv->funcCode;
        stWtCmd.datalen = (ptrMsgRecv->paramLen > MAX_WT_BUFF_LEN)?MAX_WT_BUFF_LEN:ptrMsgRecv->paramLen;
        memcpy(stWtCmd.data,ptrMsgRecv->paramData,stWtCmd.datalen);

        this->setCompleteCb(ptrMsgRecv->tarDev,NULL,NULL);

        set_wtej28_data(dp1_ele_addr_arr[ptrMsgRecv->tarDev-1],&stWtCmd,buff,&lenData);
        //set_wt184_data(&stWtCmd,buff, &lenData);
        //lenData = 10;
        //memcpy(buff,resetCmd,10);

        printf("send to rs485,len:%d\n",lenData);
        for(int i=0;i<lenData;i++)
        {
            printf("0x%02x,",buff[i]);
        }
        printf("\n");

        int isFromGrpc = (ptrMsgRecv->msgSrc == MSG_FROM_GRPC)?1:0;
        if(isFromGrpc)
        {
            printf("set status[%d] for dev[%d]\n",wontec_dev_waiting_ack, ptrMsgRecv->tarDev);
            m_status[ptrMsgRecv->tarDev] = wontec_dev_waiting_ack;   
        }
        this->send(buff,lenData);
        
        if(isFromGrpc)
        {
            if(ptrMsgRecv->funcCode == 6/*'G'*/ || ptrMsgRecv->funcCode == 8/*'E'*/)
            {
               usleep(200000);

               int max_wait_cnt = 0;
            //    if(ptrMsgRecv->funcCode == 6)
            //    {
            //        max_wait_cnt = 12;
            //    }
            //    else
            //    {
            //        max_wait_cnt = 1;
            //    }
            max_wait_cnt = 1;

               int wait_cnt = 0;

               while(m_status[ptrMsgRecv->tarDev] == wontec_dev_waiting_ack)
               {
                   usleep(200000);
                   wait_cnt++;

                   if(wait_cnt>max_wait_cnt)
                   {
                       break;
                   }
               }

               //if(wait_cnt<=max_wait_cnt)
               //{                 

                   wait_cnt = 0;
                   max_wait_cnt = 20;
                   //printf("ack received for act\n");
                   //printf("ack received for act\n");
                   while(m_status[ptrMsgRecv->tarDev] != wontec_dev_act_finished)
                   {
                       //if(wontec_dev_waiting_ack != m_status[ptrMsgRecv->tarDev])
                       //{
                            printf("prepare for querying\n",lenData);
                            wontec_485_frame expectedData;
                            memset(&expectedData,0,sizeof(wontec_485_frame));
                            expectedData.func_code = 'Q';

                            unsigned char dataTemp[2] = {'0','1'};

                            expectedData.data = dataTemp;
                            expectedData.slave_addrH = 0;
                            expectedData.slave_addrL = ptrMsgRecv->tarDev;

                            this->setCompleteCb(ptrMsgRecv->tarDev,checkProcWtej28OnPoint,&expectedData);

                            memset(&stWtCmd,0,sizeof(wontec_cmd));
                            stWtCmd.func_code = 16;
                            stWtCmd.datalen = 0;                   
                            
                            lenData = 0;
                            set_wtej28_data(dp1_ele_addr_arr[ptrMsgRecv->tarDev-1],&stWtCmd,buff,&lenData);
                            
                            m_status[ptrMsgRecv->tarDev] = wontec_dev_waiting_ack;       
                            printf("send to rs485,len:%d\n",lenData);
                            this->send(buff,lenData);
                            usleep(100000);
                            wait_cnt++;

                            if(wait_cnt>max_wait_cnt)
                            {
                                printf("query times too large\n");
                                this->setCompleteCb(ptrMsgRecv->tarDev,NULL,NULL);
                                this->sendAckToGrpc(1,2,100+ptrMsgRecv->tarDev,-1);
                                break;
                            }
                       //}
                   }
                   this->setCompleteCb(ptrMsgRecv->tarDev,NULL,NULL);

                   printf("status:%d\n",m_status[ptrMsgRecv->tarDev]);
               //}
               //else
               //{
               //    printf("time out for waiting act\n");
               //}
               

                
            }
            
        }
        
        /* code */
    }
    else if(ptrMsgRecv->tarDev == 100)
    {
        //search for all sub devs
        unsigned char lenData = 8;
        unsigned char buff[8] = {0x3E,0x24,0x43,0x42,0x31,0x31,0x0D,0x0A};
        this->send(buff,lenData);
    }
    
    
}

int CRs485::PackagePro( char* Buf, int len )
{
    wontec_485_frame frameRet;
    int parseRet = 0;
    memset(&frameRet,0,sizeof(wontec_485_frame));
    if(len>MAX_WT_BUFF_LEN)
    {
        printf("%s",Buf);
        return 1;
    }
    
    parseRet = wontec_frame_decode((unsigned char *)Buf,(unsigned char )len,&frameRet);

    if(parseRet==0)
    {
        char tempData[128];
        memset(tempData,0,128);
        memcpy(tempData,frameRet.data,frameRet.dataLen);
        printf("addr:%02x,func_code:%c,datalen:%d, data:%s\n",((frameRet.slave_addrH<<4) & 0x00f0) + (frameRet.slave_addrL&0x0f),
        frameRet.func_code,frameRet.dataLen,tempData);
        checkRecvFrame(&frameRet);
    }
    else
    {
        //printf("%s",Buf);
        for(int i=0;i<len;i++)
        {
            printf("%02x ",Buf[i]);
        }

        printf("\n");
        printf("parse failed,ret:%d\n",parseRet);
        /* code */
    }

    return 0;   
    
}


void CRs485::sendAckToGrpc(int statusCodeIn,int errorNumIn,int sid, int moduleId)
{
    msgQueueAck stMsgQueueAck;


    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));
    stMsgQueueAck.type = QUEUE_MSG_TYPE_GRPC;
    stMsgQueueAck.msg.statusCode = statusCodeIn;
    stMsgQueueAck.msg.sid = sid;
    stMsgQueueAck.msg.errorNum = errorNumIn;
    stMsgQueueAck.msg.moduleId = moduleId;
    if(msgsnd(m_idQueueMsg, (void*)&stMsgQueueAck, sizeof(msgAck), 0) < 0)
    {
        printf("send ack failed\n");
    }
   
}

void CRs485::setCompleteCb(int devId,rs485_cb ptrFuncIn,wontec_485_frame * expectedData)
{
    pthread_mutex_lock(&this->m_mutexCheckRecv);
    m_completeCbData[devId] = expectedData;
    m_completeCbFunc[devId] = ptrFuncIn;
    pthread_mutex_unlock(&this->m_mutexCheckRecv);
}

extern ob_manage * g_ptrObManage;
void CRs485::checkRecvFrame(wontec_485_frame * dataRecv)
{
    int devId = ((dataRecv->slave_addrH << 4)&0x00f0) + (dataRecv->slave_addrL & 0x000f);
    printf("in checkRecvFrame, wontec devId[%d],H[%d],L[%d]\n",devId,dataRecv->slave_addrH,dataRecv->slave_addrL);
    if(devId>=WONTEC_MAX_DEVID)
    {
        printf("devId is too large\n");
        return;
    }

    pthread_mutex_lock(&this->m_mutexCheckRecv);
    if(  m_completeCbData[devId] !=NULL 
     && m_completeCbFunc[devId] !=NULL)
     {
         printf("devId:%d,m_completeCbFunc[devId]:%08x\n",devId,m_completeCbFunc[devId]);
         int ret = m_completeCbFunc[devId](m_completeCbData[devId],dataRecv);
         if(ret == 0)
         {
             printf("devId:%d,m_status[devId]:%d\n",devId,m_status[devId]);
             m_status[devId] = wontec_dev_act_finished;

             if(g_ptrObManage)
             {
                 recvDataEleCtl stDataRecv; 
                 stDataRecv.sid = 100 + devId;
                 stDataRecv.frameType = CHECK_MOVE_END;
                 //stDataRecv.frameType = rcw;
                 g_ptrObManage->update(&stDataRecv);
             }
             
             
             this->sendAckToGrpc(0,0,100+devId,-1);
         }
         else
         {
             m_status[devId] = wontec_dev_idle;
         }
         
     }
     else
     {
        printf("set status[%d] for dev[%d]\n",wontec_dev_idle, devId);
        m_status[devId] = wontec_dev_idle;
     }
     pthread_mutex_unlock(&this->m_mutexCheckRecv);
     
}
